this._stageKeyPressId = 0;
}
}));
+ Main.overview.connect('shown', Lang.bind(this,
+ function() {
+ // If we were animating from the desktop view to the
+ // apps page the workspace page was visible, allowing
+ // the windows to animate, but now we no longer want to
+ // show it given that we are now on the apps page or
+ // search page.
+ if (this._activePage != this._workspacesPage)
+ this._workspacesPage.opacity = 0;
+ }));
Main.wm.addKeybinding('toggle-application-view',
new Gio.Settings({ schema_id: SHELL_KEYBINDINGS_SCHEMA }),
},
_toggleAppsPage: function() {
- Main.overview.show();
this._showAppsButton.checked = !this._showAppsButton.checked;
+ Main.overview.show();
},
showApps: function() {
- Main.overview.show();
this._showAppsButton.checked = true;
+ Main.overview.show();
},
show: function() {
this.reset();
-
- this._workspacesDisplay.show();
+ this._workspacesDisplay.show(this._showAppsButton.checked);
this._activePage = null;
- this._showPage(this._workspacesPage);
+ if (this._showAppsButton.checked)
+ this._showPage(this._appsPage);
+ else
+ this._showPage(this._workspacesPage);
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
Main.overview.fadeOutDesktop();
},
- zoomFromOverview: function() {
+ animateFromOverview: function() {
+ // Make sure workspace page is fully visible to allow
+ // workspace.js do the animation of the windows
+ this._workspacesPage.opacity = 255;
+
+ this._workspacesDisplay.animateFromOverview(this._activePage != this._workspacesPage);
+
this._showAppsButton.checked = false;
- this._workspacesDisplay.zoomFromOverview();
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
Main.overview.fadeInDesktop();
},
_showPage: function(page) {
+ if (!Main.overview.visible)
+ return;
+
if (page == this._activePage)
return;
const LAYOUT_SCALE_WEIGHT = 1;
const LAYOUT_SPACE_WEIGHT = 0.1;
+const WINDOW_ANIMATION_MAX_NUMBER_BLENDING = 3;
+
function _interpolate(start, end, step) {
return start + (end - start) * step;
}
return;
}
- // We will reposition windows when enter again overview anyway.
+ // We will reposition windows anyway when enter again overview or when ending the windows
+ // animations whith fade animation.
// In this way we avoid unwanted animations of windows repositioning while
- // animating overview
- if (this.leavingOverview)
+ // animating overview.
+ if (this.leavingOverview || this._animatingWindowsFade)
return;
let initialPositioning = flags & WindowPositionFlags.INITIAL;
return false;
},
- // Animate the full-screen to Overview transition.
- zoomToOverview : function() {
+ fadeToOverview: function() {
+ // We don't want to reposition windows while animating in this way.
+ this._animatingWindowsFade = true;
+ this._overviewShownId = Main.overview.connect('shown', Lang.bind(this,
+ this._doneShowingOverview));
+ if (this._windows.length == 0)
+ return;
+
+ if (this.metaWorkspace != null && this.metaWorkspace != global.screen.get_active_workspace())
+ return;
+
+ // Special case maximized windows, since it doesn't make sense
+ // to animate windows below in the stack
+ let topMaximizedWindow;
+ // It is ok to treat the case where there is no maximized
+ // window as if the bottom-most window was maximized given that
+ // it won't affect the result of the animation
+ for (topMaximizedWindow = this._windows.length - 1; topMaximizedWindow > 0; topMaximizedWindow--) {
+ let metaWindow = this._windows[topMaximizedWindow].metaWindow;
+ if (metaWindow.maximized_horizontally && metaWindow.maximized_vertically)
+ break;
+ }
+
+ let nTimeSlots = Math.min(WINDOW_ANIMATION_MAX_NUMBER_BLENDING + 1, this._windows.length - topMaximizedWindow);
+ let windowBaseTime = Overview.ANIMATION_TIME / nTimeSlots;
+
+ let topIndex = this._windows.length - 1;
+ for (let i = 0; i < this._windows.length; i++) {
+ if (i < topMaximizedWindow) {
+ // below top-most maximized window, don't animate
+ let overlay = this._windowOverlays[i];
+ if (overlay)
+ overlay.hide();
+ this._windows[i].actor.opacity = 0;
+ } else {
+ let fromTop = topIndex - i;
+ let time;
+ if (fromTop < nTimeSlots) // animate top-most windows gradually
+ time = windowBaseTime * (nTimeSlots - fromTop);
+ else
+ time = windowBaseTime;
+
+ this._windows[i].actor.opacity = 255;
+ this._fadeWindow(i, time, 0);
+ }
+ }
+ },
+
+ fadeFromOverview: function() {
+ this.leavingOverview = true;
+ this._overviewHiddenId = Main.overview.connect('hidden', Lang.bind(this,
+ this._doneLeavingOverview));
+ if (this._windows.length == 0)
+ return;
+
+ for (let i = 0; i < this._windows.length; i++) {
+ let clone = this._windows[i];
+ Tweener.removeTweens(clone.actor);
+ }
+
+ if (this._repositionWindowsId > 0) {
+ Mainloop.source_remove(this._repositionWindowsId);
+ this._repositionWindowsId = 0;
+ }
+
+ if (this.metaWorkspace != null && this.metaWorkspace != global.screen.get_active_workspace())
+ return;
+
+ // Special case maximized windows, since it doesn't make sense
+ // to animate windows below in the stack
+ let topMaximizedWindow;
+ // It is ok to treat the case where there is no maximized
+ // window as if the bottom-most window was maximized given that
+ // it won't affect the result of the animation
+ for (topMaximizedWindow = this._windows.length - 1; topMaximizedWindow > 0; topMaximizedWindow--) {
+ let metaWindow = this._windows[topMaximizedWindow].metaWindow;
+ if (metaWindow.maximized_horizontally && metaWindow.maximized_vertically)
+ break;
+ }
+
+ let nTimeSlots = Math.min(WINDOW_ANIMATION_MAX_NUMBER_BLENDING + 1, this._windows.length - topMaximizedWindow);
+ let windowBaseTime = Overview.ANIMATION_TIME / nTimeSlots;
+
+ let topIndex = this._windows.length - 1;
+ for (let i = 0; i < this._windows.length; i++) {
+ if (i < topMaximizedWindow) {
+ // below top-most maximized window, don't animate
+ let overlay = this._windowOverlays[i];
+ if (overlay)
+ overlay.hide();
+ this._windows[i].actor.opacity = 0;
+ } else {
+ let fromTop = topIndex - i;
+ let time;
+ if (fromTop < nTimeSlots) // animate top-most windows gradually
+ time = windowBaseTime * (fromTop + 1);
+ else
+ time = windowBaseTime * nTimeSlots;
+
+ this._windows[i].actor.opacity = 0;
+ this._fadeWindow(i, time, 255);
+ }
+ }
+ },
+
+ _fadeWindow: function(index, time, opacity) {
+ let clone = this._windows[index];
+ let overlay = this._windowOverlays[index];
+
+ if (overlay)
+ overlay.hide();
+
+ if (clone.metaWindow.showing_on_its_workspace()) {
+ let [origX, origY] = clone.getOriginalPosition();
+ clone.actor.scale_x = 1;
+ clone.actor.scale_y = 1;
+ clone.actor.x = origX;
+ clone.actor.y = origY;
+ Tweener.addTween(clone.actor,
+ { time: time,
+ opacity: opacity,
+ transition: 'easeOutQuad'
+ });
+ } else {
+ // The window is hidden
+ clone.actor.opacity = 0;
+ }
+ },
+
+ zoomToOverview: function() {
// Position and scale the windows.
this._recalculateWindowPositions(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
},
- // Animates the return from Overview mode
- zoomFromOverview : function() {
+ zoomFromOverview: function() {
let currentWorkspace = global.screen.get_active_workspace();
this.leavingOverview = true;
return;
// Position and scale the windows.
- for (let i = 0; i < this._windows.length; i++) {
- let clone = this._windows[i];
- let overlay = this._windowOverlays[i];
-
- if (overlay)
- overlay.hide();
+ for (let i = 0; i < this._windows.length; i++)
+ this._zoomWindowFromOverview(i);
+ },
- if (clone.metaWindow.showing_on_its_workspace()) {
- let [origX, origY] = clone.getOriginalPosition();
-
- Tweener.addTween(clone.actor,
- { x: origX,
- y: origY,
- scale_x: 1.0,
- scale_y: 1.0,
- time: Overview.ANIMATION_TIME,
- opacity: 255,
- transition: 'easeOutQuad'
- });
- } else {
- // The window is hidden, make it shrink and fade it out
- Tweener.addTween(clone.actor,
- { scale_x: 0,
- scale_y: 0,
- opacity: 0,
- time: Overview.ANIMATION_TIME,
- transition: 'easeOutQuad'
- });
- }
+ _zoomWindowFromOverview: function(index) {
+ let clone = this._windows[index];
+ let overlay = this._windowOverlays[index];
+
+ if (overlay)
+ overlay.hide();
+
+ if (clone.metaWindow.showing_on_its_workspace()) {
+ let [origX, origY] = clone.getOriginalPosition();
+ Tweener.addTween(clone.actor,
+ { x: origX,
+ y: origY,
+ scale_x: 1.0,
+ scale_y: 1.0,
+ time: Overview.ANIMATION_TIME,
+ opacity: 255,
+ transition: 'easeOutQuad'
+ });
+ } else {
+ // The window is hidden, make it shrink and fade it out
+ Tweener.addTween(clone.actor,
+ { scale_x: 0,
+ scale_y: 0,
+ opacity: 0,
+ time: Overview.ANIMATION_TIME,
+ transition: 'easeOutQuad'
+ });
}
},
this.leavingOverview = false;
},
+ _doneShowingOverview: function() {
+ this._animatingWindowsFade = false;
+ this._recalculateWindowPositions(WindowPositionFlags.INITIAL);
+ },
+
// Tests if @actor belongs to this workspaces and monitor
_isMyWindow : function (actor) {
let win = actor.meta_window;
// Note that mutter has a compile-time limit of 36
const MAX_WORKSPACES = 16;
+const AnimationType = {
+ ZOOM: 0,
+ FADE: 1
+};
+
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
const WorkspacesViewBase = new Lang.Class({
return this._workspaces[active];
},
- zoomToOverview: function() {
- for (let w = 0; w < this._workspaces.length; w++)
- this._workspaces[w].zoomToOverview();
+ animateToOverview: function(animationType) {
+ for (let w = 0; w < this._workspaces.length; w++) {
+ if (animationType == AnimationType.ZOOM)
+ this._workspaces[w].zoomToOverview();
+ else
+ this._workspaces[w].fadeToOverview();
+ }
this._updateWorkspaceActors(false);
},
- zoomFromOverview: function() {
+ animateFromOverview: function(animationType) {
this.actor.remove_clip();
- for (let w = 0; w < this._workspaces.length; w++)
- this._workspaces[w].zoomFromOverview();
+ for (let w = 0; w < this._workspaces.length; w++) {
+ if (animationType == AnimationType.ZOOM)
+ this._workspaces[w].zoomFromOverview();
+ else
+ this._workspaces[w].fadeFromOverview();
+ }
},
syncStacking: function(stackIndices) {
this._workspace.setActualGeometry(this._actualGeometry);
},
- zoomToOverview: function() {
- this._workspace.zoomToOverview();
+ animateToOverview: function(animationType) {
+ if (animationType == AnimationType.ZOOM)
+ this._workspace.zoomToOverview();
+ else
+ this._workspace.fadeToOverview();
},
- zoomFromOverview: function() {
- this._workspace.zoomFromOverview();
+ animateFromOverview: function(animationType) {
+ if (animationType == AnimationType.ZOOM)
+ this._workspace.zoomFromOverview();
+ else
+ this._workspace.fadeFromOverview();
},
syncStacking: function(stackIndices) {
return this._getPrimaryView().actor.navigate_focus(from, direction, false);
},
- show: function() {
+ show: function(fadeOnPrimary) {
this._updateWorkspacesViews();
- for (let i = 0; i < this._workspacesViews.length; i++)
- this._workspacesViews[i].zoomToOverview();
+ for (let i = 0; i < this._workspacesViews.length; i++) {
+ let animationType;
+ if (fadeOnPrimary && i == this._primaryIndex)
+ animationType = AnimationType.FADE;
+ else
+ animationType = AnimationType.ZOOM;
+ this._workspacesViews[i].animateToOverview(animationType);
+ }
this._restackedNotifyId =
Main.overview.connect('windows-restacked',
this._scrollEventId = Main.overview.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
},
- zoomFromOverview: function() {
- for (let i = 0; i < this._workspacesViews.length; i++)
- this._workspacesViews[i].zoomFromOverview();
+ animateFromOverview: function(fadeOnPrimary) {
+ for (let i = 0; i < this._workspacesViews.length; i++) {
+ let animationType;
+ if (fadeOnPrimary && i == this._primaryIndex)
+ animationType = AnimationType.FADE;
+ else
+ animationType = AnimationType.ZOOM;
+ this._workspacesViews[i].animateFromOverview(animationType);
+ }
},
hide: function() {